home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Speccy ClassiX 1998
/
Speccy ClassiX 98.iso
/
amiga_system
/
the_aminet
/
dev
/
gcc
/
ixemulsrc.lha
/
ixemul-41.4
/
stdlib
/
ssystem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-28
|
9KB
|
324 lines
/*
* This file is part of ixemul.library for the Amiga.
* Copyright (C) 1991, 1992 Markus M. Wild
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* 22-jan-92 -mw- restore sigmask before calling system()
*/
#define KERNEL
#include "ixemul.h"
#include "kprintf.h"
#include <ctype.h>
#include <sys/wait.h>
/* 2.0 support */
#include <utility/tagitem.h>
#include <dos/dostags.h>
#include <hardware/intbits.h>
#if __GNUC__ != 2
#define alloca __builtin_alloca
#endif
extern BPTR *__load_seg (char *name, char **args);
int
ssystem(char *argline)
{
int rc, err = 0;
UBYTE *arg, *index();
UBYTE *tmp;
int stack_size;
struct CommandLineInterface *CLI;
struct Process *me;
int omask;
void *old_trapdata, *old_trapcode;
int old_flags;
void *old_launch, *old_switch;
omask = syscall (SYS_sigsetmask, ~0);
me = (struct Process *)FindTask(0);
CLI = BTOCPTR (me->pr_CLI);
stack_size = CLI ? CLI->cli_DefaultStack * 4 : me->pr_StackSize;
if (stack_size <= 4096) stack_size = 250000;
/* the +1 is to get a cheap way to transform this into a BSTR */
tmp = alloca (strlen (argline) + 6);
tmp = LONG_ALIGN (tmp);
tmp++;
strcpy (tmp, argline);
while (*tmp == ' ' || *tmp == '\t') ++tmp;
/* not needed with custom load-seg function */
if (arg = index(tmp, ' ')) *arg++ = 0;
{
BPTR *segs;
char *args;
BPTR old_cis, old_cos, old_ces;
BPTR dup_cis, dup_cos, dup_ces;
struct file *f;
segs = __load_seg (tmp, &args);
/* check for special cookie */
if (segs == (BPTR *) -2)
{
syscall (SYS_sigsetmask, omask);
/* let the shell do the dirty work ;-)) */
return system (argline);
}
if (segs)
{
char **name;
char *orig;
char *all_args;
u_int old_signals;
/* if __load_seg() set args to something, we have to rebuild our
* command line, but only just in that case ;-))
*/
if (args)
{
int force_quotes = 0;
/* now this IS a horrible kludge.. but again, I *NEED* sksh
* working, and it only works, if the argument to the -c
* switch is passed quoted... So if the __load_seg code
* decided, that this was such a special sksh-script, it
* negates the *arg parameter... shudder...
*
* NOTE: This only works for command lines that contain no
* quotes themselves... I don't escape the argument
* line, I just put a pair of quotes around it!
* The starting quote is already included in the args
* string from __load_seg()...
*/
if (((int)args) < 0)
{
force_quotes = 1;
args = (char *) ((-(int)args));
}
/* make handling easier */
if (! arg) arg = "";
/* the command we build looks like:
* <seg'd command> args arg
*/
all_args = alloca (strlen (args) + 1 + strlen (arg) + 4);
strcpy (all_args, args);
if (*arg)
{
strcat (all_args, " ");
strcat (all_args, arg);
}
if (force_quotes)
strcat (all_args, "\""); /* no comment... */
strcat (all_args, "\n"); /* neither, this insn't my kludge though.. */
/* and finally reassign the commandline to arg */
arg = all_args;
/* if args was not "", we have to free it, it's from strdup() */
if (*args) syscall (SYS_free, args);
}
else
{
/* even if we didn't get any arguments from the expander, we still
* need to protect the original arguments ala BCPL ..
* Remember that `arg' is a (large enough) alloca() string ;-) */
if (arg)
strcat (arg, "\n");
else
arg = "\n";
}
/*
* Hack to always get the name of the currently executing program
* to show up in Xoper
*/
if (CLI)
{
name = (char **) & CLI->cli_CommandName;
orig = *name;
/* that's why we incremented tmp before ;-)) */
((unsigned char *)tmp)[-1] = strlen (tmp);
/* this is always odd (stack=even + 1), so will chop fine to BPTR */
*name = (char *) ((long)tmp >> 2);
}
else
{
name = (char **) & me->pr_Task.tc_Node.ln_Name;
orig = *name;
*name = tmp;
}
KPRINTF (("RunCommand (stack_size=%ld, arg = >%s<, len = %ld)\n", stack_size, arg, strlen (arg)));
/* perform I/O redirection... (copied from execve.c) */
if ((f = u.u_ofile[0]) && f->f_type == DTYPE_FILE)
{
dup_cis = 0;
old_cis = SelectInput (CTOBPTR (f->f_fh));
readargs_kludge (CTOBPTR (f->f_fh));
KPRINTF (("redir 0, old_cis = $%lx\n",old_cis));
}
else
{
if (!f)
{
int fd = open ("/dev/null", 0);
dup_cis = dup2_BPTR (fd);
close (fd);
}
else
dup_cis = dup2_BPTR (0);
old_cis = 0;
if (dup_cis)
{
old_cis = SelectInput (dup_cis);
readargs_kludge (dup_cis);
KPRINTF (("redir 0, old_cis = $%lx, dup_cis = $%lx\n", old_cis, dup_cis));
}
else
KPRINTF (("redir 0, dup2_BPTR failed\n"));
}
if ((f = u.u_ofile[1]) && f->f_type == DTYPE_FILE)
{
dup_cos = 0;
old_cos = SelectOutput (CTOBPTR (f->f_fh));
KPRINTF (("redir 1, old_cos = $%lx\n", old_cos));
}
else
{
if (!f)
{
int fd = open ("/dev/null", 1);
dup_cos = dup2_BPTR (fd);
close (fd);
}
else
dup_cos = dup2_BPTR (1);
old_cos = 0;
if (dup_cos)
{
old_cos = SelectOutput (dup_cos);
KPRINTF (("redir 1, old_cos = $%lx, dup_cos = $%lx\n", old_cos, dup_cos));
}
else
KPRINTF (("redir 1, dup2_BPTR failed\n"));
}
old_ces = me->pr_CES;
if ((f = u.u_ofile[2]) && f->f_type == DTYPE_FILE)
{
dup_ces = 0;
me->pr_CES = CTOBPTR (f->f_fh);
}
else
{
if (!f)
{
int fd = open ("/dev/null", 2);
dup_ces = dup2_BPTR (fd);
close (fd);
}
else
dup_ces = dup2_BPTR (2);
me->pr_CES = dup_ces ? : old_ces;
}
/* cleanup as much of ixemul.library as possible, so that the started
process can take over */
old_flags = me->pr_Task.tc_Flags;
me->pr_Task.tc_Flags = u_save.u_otask_flags;
old_launch = me->pr_Task.tc_Launch;
me->pr_Task.tc_Launch = u_save.u_olaunch; /* restoring this disables our signals */
old_switch = me->pr_Task.tc_Switch;
me->pr_Task.tc_Switch = u_save.u_oswitch;
RemIntServer (INTB_VERTB, & u_save.u_itimerint);
/* BEWARE that after this reset no library functions can be
called any longer until the moment where trapdata is
reinstalled !! */
old_trapdata = me->pr_Task.tc_TrapData;
me->pr_Task.tc_TrapData = u_save.u_otrap_data;
old_trapcode = me->pr_Task.tc_TrapCode;
me->pr_Task.tc_TrapCode = u_save.u_otrap_code;
/* RunCommand should provide the started program with a fresh set of
* signals, it doesn't. So we do this by hand here... */
old_signals = me->pr_Task.tc_SigAlloc;
me->pr_Task.tc_SigAlloc &= 0xffff;
rc = RunCommand (*segs, stack_size, arg, strlen (arg));
me->pr_Task.tc_TrapData = old_trapdata;
me->pr_Task.tc_TrapCode = old_trapcode;
KPRINTF (("RunCommand back, stack_size = %ld, rc = %ld, sp = $%lx\n", stack_size, rc, get_sp()));
me->pr_Task.tc_SigAlloc = old_signals;
err = __ioerr_to_errno (IoErr ());
*name = orig;
AddIntServer (INTB_VERTB, & u_save.u_itimerint);
me->pr_Task.tc_Launch = old_launch;
me->pr_Task.tc_Switch = old_switch;
me->pr_Task.tc_Flags = old_flags;
if (old_cis)
SelectInput (old_cis);
if (old_cos)
SelectOutput (old_cos);
me->pr_CES = old_ces;
/* reset I/O */
if (dup_cis)
Close (dup_cis);
if (dup_cos)
Close (dup_cos);
if (dup_ces)
Close (dup_ces);
__free_seg (segs);
}
else
{
rc = 20;
err = __ioerr_to_errno (IoErr ());
}
}
syscall (SYS_sigsetmask, omask);
if (rc > 128)
errno = EINTR;
else
errno = err;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return (rc >= 128) ? W_EXITCODE (0, rc & 0x7f) : W_EXITCODE (rc, 0);
}